home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Franz PD / Franz PD Disk #067 (1990-04)(Amiga User Group Deutschland e.V.).zip / Franz PD Disk #067 (1990-04)(Amiga User Group Deutschland e.V.).adf / Source.zip / Utilities.p < prev   
Text File  |  1989-12-02  |  15KB  |  724 lines

  1. external;
  2.  
  3. {
  4.     Utilities.p (of PCQ Pascal)
  5.     Copyright (c) 1989 Patrick Quaid.
  6.  
  7.     This module handles the various tables and whatever
  8.     run-time business the compiler might have.
  9. }
  10.  
  11. {$O-}
  12. {$I "Pascal.i"}
  13. {$I "Include/StringLib.i"}
  14. {$I "Include/Exec.i"}
  15.  
  16.     Procedure Error(s : string);
  17.         external;
  18.     Procedure NextSymbol;
  19.         external;
  20.     Procedure Abort;
  21.         external;
  22.     Procedure PushLongD0;
  23.         external;
  24.     Procedure PushLongD1;
  25.         External;
  26.     Procedure PopLongD1;
  27.         external;
  28.     Procedure PopLongD0;
  29.         External;
  30.  
  31. Procedure NewSpell;
  32. var
  33.     TempPtr : SpellRecPtr;
  34. begin
  35.     New(TempPtr);
  36.     TempPtr^.Previous := CurrentSpellRec;
  37.     CurrentSpellRec := TempPtr;
  38.     CurrentSpellRec^.First := SpellPtr;
  39. end;
  40.  
  41. Procedure BackUpSpell(Position : Integer);
  42. var
  43.     TempPtr : SpellRecPtr;
  44. begin
  45.     while Position < CurrentSpellRec^.First do begin
  46.     TempPtr := CurrentSpellRec^.Previous;
  47.     Dispose(CurrentSpellRec);
  48.     CurrentSpellRec := TempPtr;
  49.     end;
  50.     SpellPtr := Position;
  51. end;
  52.  
  53. Function EnterSpell(S : String) : String;
  54. var
  55.     Length : Integer;
  56.     Result : String;
  57. begin
  58.     Length := strlen(S) + 1;
  59.     if (Length + SpellPtr) - CurrentSpellRec^.First > Spell_Max then
  60.     NewSpell;
  61.     Result := Adr(CurrentSpellRec^.Data[SpellPtr - CurrentSpellRec^.First]);
  62.     strcpy(Result, S);
  63.     SpellPtr := SpellPtr + Length;
  64.     EnterSpell := Result;
  65. end;
  66.  
  67. Function SimpleType(testtype : TypePtr) : Boolean;
  68.  
  69. {
  70.     If a variable passes this test, it is held in a register
  71. during processing.  If not, the address of the variable is held in
  72. the register.  This is the main reason why type conversions don't
  73. work across all types of the same size.
  74. }
  75.  
  76. begin
  77.     SimpleType := (TestType^.Size <= 4) and
  78.           (TestType^.Size <> 3) and
  79.           (TestType^.Object <> ob_record) and
  80.           (TestType^.Object <> ob_array);
  81. end;
  82.  
  83. Function BaseType(orgtype : TypePtr): TypePtr;
  84.  
  85. {
  86.     This routine returns the base type of type.  If this
  87. routine is used consistently, ranges and subtypes will work with
  88. some consistency.
  89. }
  90.  
  91. begin
  92.     while (orgtype^.Object = ob_subrange) or (orgtype^.Object = ob_synonym) do
  93.     orgtype := orgtype^.SubType;
  94.     basetype := orgtype;
  95. end;
  96.  
  97. Function HigherType(typea, typeb : TypePtr): TypePtr;
  98.  
  99. {
  100.     This routine returns the more complex type of the two
  101. numeric types passed to it.  In other words a 32 bit integer is
  102. 'higher' than a 16 bit one.
  103. }
  104.  
  105. begin
  106.     if (TypeA = RealType) or (TypeB = RealType) then
  107.     HigherType := RealType;
  108.     if (typea = inttype) or (typeb = inttype) then
  109.     highertype := inttype;
  110.     if (typea = shorttype) or (typeb = shorttype) then
  111.     highertype := shorttype;
  112.     highertype := typea;
  113. end;
  114.  
  115. Procedure PromoteType(var from : TypePtr; other : TypePtr; reg : Short);
  116.  
  117. {
  118.     This routine extends reg as necessary to make the 'from'
  119. type equivalent to 'other'.
  120. }
  121.  
  122. var
  123.     totype : TypePtr;
  124. begin
  125.     from := basetype(from);
  126.     other := basetype(other);
  127.     totype := highertype(from, other);
  128.     if from = totype then
  129.     return;
  130.     if totype = realtype then begin
  131.     if from = bytetype then
  132.         writeln(OutFile, "\tand.l\t#255,d",reg)
  133.     else if from = shorttype then
  134.         writeln(OutFile, "\text.l\td",reg);
  135.     if reg = 0 then
  136.         PushLongD1
  137.     else begin
  138.         PushLongD0;
  139.         writeln(OutFile, "\tmove.l\td1,d0");
  140.     end;
  141.     writeln(OutFile, "\tmove.l\t_p%MathBase,a6");
  142.     writeln(OutFile, "\tjsr\t-36(a6)");        { _LVOSPFlt }
  143.     if reg = 0 then
  144.         PopLongD1
  145.     else begin
  146.         writeln(OutFile, "\tmove.l\td0,d1");
  147.         PopLongD0;
  148.     end;
  149.     from := RealType;
  150.     end else if totype = inttype then begin
  151.     if from = shorttype then
  152.         writeln(OutFile, "\text.l\td", reg)
  153.     else if from = bytetype then
  154.         writeln(OutFile, "\tand.l\t#255,d", reg);
  155.     from := inttype;
  156.     end else if totype = shorttype then begin
  157.     if from = bytetype then
  158.         writeln(OutFile, "\tand.w\t#255,d", reg);
  159.     from := shorttype;
  160.     end;
  161. end;
  162.  
  163. Procedure NewBlock;
  164. var
  165.     CB : BlockPtr;
  166.     i  : Short;
  167. begin
  168.     New(CB);
  169.     CB^.FirstType := Nil;
  170.     for i := 0 to Hash_Size do
  171.     CB^.Table[i] := Nil;
  172.     if CurrentBlock = Nil then
  173.     CB^.Level := 0
  174.     else
  175.     CB^.Level := Succ(CurrentBlock^.Level);
  176.     CB^.Previous := CurrentBlock;
  177.     CurrentBlock := CB;
  178. end;
  179.  
  180. Procedure KillIDList(ID : IDPtr);
  181. var
  182.     TempID : IDPtr;
  183. begin
  184.     while ID <> Nil do begin
  185.     if (ID^.Object = proc) or (ID^.Object = func) then
  186.         KillIDList(ID^.Param);
  187.     TempID := ID^.Next;
  188.     Dispose(ID);
  189.     ID := TempID;
  190.     end;
  191. end;
  192.  
  193. Procedure KillBlock;
  194. var
  195.     CB : BlockPtr;
  196.     ID : IDPtr;
  197.     TP : TypePtr;
  198.     i  : Integer;
  199.  
  200.     Procedure KillTypeList(TP : TypePtr);
  201.     var
  202.     TempType : TypePtr;
  203.     begin
  204.     while TP <> nil do begin
  205.         if TP^.Object = ob_record then
  206.         KillIDList(TP^.Ref);
  207.         TempType := TP^.Next;
  208.         Dispose(TP);
  209.         TP := TempType;
  210.     end;
  211.     end;
  212.  
  213. begin
  214.     CB := CurrentBlock;
  215.     CurrentBlock := CurrentBlock^.Previous;
  216.     for i := 0 to Hash_Size do
  217.     KillIDList(CB^.Table[i]);
  218.     KillTypeList(CB^.FirstType);
  219. end;
  220.  
  221. Function Match(sym : Symbols): Boolean;
  222.  
  223. {
  224.     If the current symbol is sym, return true and get the
  225. next one.
  226. }
  227.  
  228. begin
  229.     if CurrSym = Sym then begin
  230.     NextSymbol;
  231.     Match := True;
  232.     end else
  233.     Match := False;
  234. end;
  235.  
  236. {
  237.     The following routines just print out common error messages
  238. and make some common tests.
  239. }
  240.  
  241. procedure Mismatch;
  242. begin
  243.     error("Mismatched types");
  244. end;
  245.  
  246. procedure NeedNumber;
  247. begin
  248.     error("Need a numeric type");
  249. end;
  250.  
  251. procedure NoLeftParent;
  252. begin
  253.     error("No left parenthesis");
  254. end;
  255.  
  256. procedure NoRightParent;
  257. begin
  258.     error("No right parenthesis");
  259. end;
  260.  
  261. procedure NeedLeftParent;
  262. begin
  263.     if not match(leftparent1) then
  264.     noleftparent;
  265. end;
  266.  
  267. procedure NeedRightParent;
  268. begin
  269.     if not match(rightparent1) then
  270.     norightparent;
  271. end;
  272.  
  273. {
  274. Function Hash(s : String) : Short;
  275. var
  276.     c : Char;
  277.     i : Short;
  278.     result : Integer;
  279. begin
  280.     result := strlen(s);
  281.     i := 0;
  282.     while s[i] <> Chr(0) do begin
  283.     c := toupper(s[i]);
  284.     result := ((result * 13 + Ord(c)) and $07ff);
  285.     i := Succ(i);
  286.     end;
  287.     Hash := Result and Hash_Size;
  288. end;
  289. }
  290.  
  291. Procedure EnterID(EntryBlock : BlockPtr; ID : IDPtr);
  292. var
  293.     HVal : Short;
  294. begin
  295.     ID^.Level := EntryBlock^.Level;
  296.     HVal := Hash(ID^.Name) and Hash_Size;
  297.     ID^.Next := EntryBlock^.Table[HVal];
  298.     EntryBlock^.Table[HVal] := ID;
  299. end;
  300.  
  301. Function EnterStandard( st_Name : String;
  302.             st_Object : IDObject;
  303.             st_Type : TypePtr;
  304.             st_Storage : IDStorage;
  305.             st_Offset  : Integer)    : IDPtr;
  306. var
  307.     ID : IDPtr;
  308. begin
  309.     new(ID);
  310.     ID^.Next := Nil;
  311.     ID^.Name := EnterSpell(st_Name);
  312.     ID^.Object := st_Object;
  313.     ID^.VType := st_Type;
  314.     ID^.Param := Nil;
  315.     ID^.Storage := st_Storage;
  316.     ID^.Offset := st_Offset;
  317.     EnterID(CurrentBlock, ID);
  318.     EnterStandard := ID;
  319. end;
  320.  
  321. Procedure ns;
  322.  
  323. {
  324.     This routine just tests for a semicolon.
  325. }
  326.  
  327. begin
  328.     if not match(semicolon1) then begin
  329.     if (currsym <> end1) and (currsym <> else1) and (currsym <> until1) then
  330.         error("missing semicolon");
  331.     end else
  332.     while match(semicolon1) do;
  333. end;
  334.  
  335. Function TypeCmp(TypeA, TypeB : TypePtr) : Boolean;
  336.  
  337. {
  338.     This routine just compares two types to see if they're
  339. equivalent.  Subranges of the same type are considered equivalent.
  340. Note that 'badtype' is actually a universal type used when there
  341. are errors, in order to avoid streams of errors.
  342. }
  343.  
  344. var
  345.     t1ptr,
  346.     t2ptr  : IDPtr;
  347. begin
  348.     TypeA := BaseType(TypeA);
  349.     TypeB := BaseType(TypeB);
  350.  
  351.     if TypeA = TypeB then
  352.     TypeCmp := True;
  353.     if (TypeA = BadType) or (TypeB = BadType) then
  354.     TypeCmp := True;
  355.     if TypeA^.Object <> TypeB^.Object then
  356.     typecmp := false;
  357.     if TypeA^.Object = ob_array then begin
  358.     if (TypeA^.Upper - TypeA^.Lower) <>
  359.        (TypeB^.Upper - TypeB^.Lower) then
  360.         typecmp := false;
  361.     TypeCmp := TypeCmp(TypeA^.Subtype, TypeB^.SubType);
  362.     end;
  363.     if TypeA^.Object = ob_pointer then
  364.     TypeCmp := TypeCmp(TypeA^.SubType, TypeB^.SubType);
  365.     if TypeA^.Object = ob_file then
  366.     TypeCmp := TypeCmp(TypeA^.SubType, TypeB^.Subtype);
  367.     TypeCmp := false;
  368. end;
  369.  
  370. Function NumberType(testtype : TypePtr) : Boolean;
  371.  
  372. {
  373.     Return true if this is a numeric type.
  374. }
  375.  
  376. begin
  377.     TestType := BaseType(TestType);
  378.     if TestType = IntType then
  379.     NumberType := true
  380.     else if TestType = ShortType then
  381.     NumberType := True
  382.     else if TestType = ByteType then
  383.     NumberType := True;
  384.     NumberType := False;
  385. end;
  386.  
  387. Function TypeCheck(TypeA, TypeB : TypePtr) : Boolean;
  388.  
  389. {
  390.     This is similar to typecmp, but considers numeric types
  391. equivalent.
  392. }
  393.  
  394. begin
  395.     TypeA := BaseType(TypeA);
  396.     TypeB := BaseType(TypeB);
  397.     if TypeA = TypeB then
  398.     TypeCheck := True;
  399.     if NumberType(TypeA) and NumberType(TypeB) then
  400.     TypeCheck := True;
  401.     TypeCheck := TypeCmp(TypeA, TypeB);
  402. end;
  403.  
  404. Function AddType(at_Object : TypeObject;
  405.          at_SubType: TypePtr;
  406.          at_Ref    : Address;
  407.          at_Upper,
  408.          at_Lower,
  409.          at_Size   : Integer) : TypePtr;
  410.  
  411. {
  412.     Adds a type to the id array.
  413. }
  414.  
  415. var
  416.     TP    : TypePtr;
  417. begin
  418.     New(TP);
  419.     TP^.Object := at_Object;
  420.     TP^.SubType := at_SubType;
  421.     TP^.Ref := at_Ref;
  422.     TP^.Upper := at_Upper;
  423.     TP^.Lower := at_Lower;
  424.     TP^.Size  := at_Size;
  425.     TP^.Next  := CurrentBlock^.FirstType;
  426.     CurrentBlock^.FirstType := TP;
  427.     AddType := TP;
  428. end;
  429.  
  430. Function FindID(idname : string): IDPtr;
  431. { Find the most local reference to a variable }
  432. var
  433.     ID    : IDPtr;
  434.     CB  : BlockPtr;
  435.     HVal : Short;
  436. begin
  437.     CB := CurrentBlock;
  438.     HVal := Hash(idname) and Hash_Size;
  439.     while CB <> nil do begin
  440.     ID := CB^.Table[HVal];
  441.     while ID <> nil do begin
  442.         if strieq(idname, ID^.Name) then
  443.         FindID := ID;
  444.         ID := ID^.Next;
  445.     end;
  446.     CB := CB^.Previous;
  447.     end;
  448.     FindID := Nil;
  449. end;
  450.  
  451. Function CheckID(idname : string): IDPtr;
  452.  
  453. {
  454.     This is like the above, but only checks the current block.
  455. }
  456.  
  457. var
  458.     ID : IDPtr;
  459. begin
  460.     ID := CurrentBlock^.Table[Hash(idname) and Hash_Size];
  461.     while ID <> nil do begin
  462.     if strieq(idname, ID^.Name) then
  463.         CheckID := ID;
  464.     ID := ID^.Next;
  465.     end;
  466.     CheckID := Nil;
  467. end;
  468.  
  469. Function CheckIDList(S : String; ID : IDPtr) : Boolean;
  470. begin
  471.     while ID <> nil do begin
  472.     if strieq(S, ID^.Name) then
  473.         CheckIDList := True;
  474.     ID := ID^.Next;
  475.     end;
  476.     CheckIDList := False;
  477. end;
  478.  
  479. Function FindField(idname : string; RecType : TypePtr) : IDPtr;
  480.  
  481. {
  482.     This just finds the appropriate field, given the index of
  483. the record type.
  484.  
  485. }
  486.  
  487. var
  488.     ID    : IDPtr;
  489. begin
  490.     ID := RecType^.Ref;
  491.     while ID <> Nil do begin
  492.     if strieq(idname, ID^.Name) then
  493.         FindField := ID;
  494.     ID := ID^.Next;
  495.     end;
  496.     FindField := Nil;
  497. end;
  498.  
  499. Function FindWithField(Str : String) : IDPtr;
  500. var
  501.     CurrentWith : WithRecPtr;
  502.     ID : IDPtr;
  503. begin
  504.     CurrentWith := FirstWith;
  505.     while CurrentWith <> Nil do begin
  506.     ID := FindField(Str, CurrentWith^.RecType);
  507.     if ID <> Nil then begin
  508.         LastWith := CurrentWith;
  509.         FindWithField := ID;
  510.     end;
  511.     CurrentWith := CurrentWith^.Previous;
  512.     end;
  513.     FindWithField := Nil;
  514. end;
  515.  
  516. Function IsVariable(ID : IDPtr) : Boolean;
  517.  
  518. {
  519.     Returns true if index is a variable.
  520. }
  521.  
  522. begin
  523.     case ID^.Object of
  524.     local,
  525.     refarg,
  526.     valarg,
  527.     global,
  528.     typed_const,
  529.     field    : IsVariable := True;
  530.     else
  531.     IsVariable := False;
  532.     end;
  533. end;
  534.  
  535. Function Suffix(size : integer): char;
  536.  
  537. {
  538.     Returns the proper assembly language suffix for the various
  539. operations.
  540. }
  541.  
  542. begin
  543.     if size = 1 then
  544.     suffix := 'b'
  545.     else if size = 2 then
  546.     suffix := 'w'
  547.     else if size = 4 then
  548.     suffix := 'l'
  549.     else {must be a bug!}
  550.     suffix := '!';
  551. end;
  552.  
  553. {
  554. Procedure WriteTabs(Tabs : Short);
  555. var
  556.    I : Short;
  557. begin
  558.     I := 0;
  559.     while I < Tabs do begin
  560.     Write(' ');
  561.     I := Succ(I);
  562.     end;
  563. end;
  564.  
  565. Procedure WriteID(ID : IDPtr; Tabs : Short; Primary : Boolean);
  566.     forward;
  567.  
  568. Procedure WriteType(TP : TypePtr; Tabs : Short; Primary : Boolean);
  569. var
  570.     ID : IDPtr;
  571. begin
  572.     if CheckBreak() then
  573.     Abort;
  574.     case TP^.Object of
  575.     ob_array : begin
  576.              write('Array [', TP^.lower, '..', TP^.upper, '] of ');
  577.              WriteType(TP^.SubType, Tabs, True);
  578.            end;
  579.     ob_record : begin
  580.             Write('Record');
  581.             if not Primary then
  582.                 return
  583.             else
  584.                 Writeln;
  585.             ID := TP^.Ref;
  586.             while ID <> Nil do begin
  587.                 WriteID(ID, Tabs + 4, False);
  588.                 ID := ID^.Next;
  589.             end;
  590.             WriteTabs(Tabs);
  591.             Write('END');
  592.             end;
  593.     ob_ordinal : begin
  594.             if TP = IntType then
  595.                 Write('Integer')
  596.             else if TP = ShortType then
  597.                 Write('Short')
  598.             else if TP = BoolType then
  599.                 Write('Boolean')
  600.             else if TP = CharType then
  601.                 Write('Char')
  602.             else if TP = ByteType then
  603.                 Write('Byte')
  604.             else if TP = BadType then
  605.                 Write('Universal')
  606.             else
  607.                 Write('Enumerated');
  608.             end;
  609.     ob_pointer : begin
  610.             write('^');
  611.             WriteType(TP^.SubType, Tabs, Primary);
  612.             end;
  613.     ob_file   : begin
  614.             if TP = TextType then
  615.                 Write('Text')
  616.             else begin
  617.                 write('File of ');
  618.                 WriteType(TP^.SubType,Tabs, True);
  619.             end;
  620.             end;
  621.     ob_real   : Write('Real');
  622.     ob_subrange : begin
  623.             Write(TP^.Lower, ' .. ', TP^.Upper, ' of ');
  624.             WriteType(TP^.SubType, Tabs, True);
  625.               end;
  626.     end;
  627. end;
  628.                 
  629. procedure WriteID(ID : IDPtr; Tabs : Short; Primary : Boolean);
  630. var
  631.     TempID : IDPtr;
  632. begin
  633.     if CheckBreak() then
  634.     Abort;
  635.     WriteTabs(Tabs);
  636.     case ID^.Object of
  637.     global,
  638.     local    : write('VAR ');
  639.     refarg    : write('REF ');
  640.     valarg    : write('VAL ');
  641.     typed_const : write('IVAR ');
  642.     proc,
  643.     stanproc: write('Procedure ');
  644.     stanfunc,
  645.     func    : write('Function  ');
  646.     obtype    : write('TYPE ');
  647.     constant : write('CONST ');
  648.     end;
  649.     if ID^.Name = nil then
  650.     Write('""')
  651.     else
  652.     Write(ID^.Name);
  653.     if (ID^.Object = proc) or (ID^.Object = func) then begin
  654.     TempID := ID^.Param;
  655.     write('(');
  656.     while TempID <> nil do begin
  657.         WriteID(TempID, Tabs + 4, True);
  658.         TempID := TempID^.Next;
  659.     end;
  660.     write(')');
  661.     end;
  662.     if (ID^.Object <> proc) and (ID^.Object <> stanproc) then begin
  663.     if (ID^.Object = constant) or (ID^.Object = refarg) or
  664.        (ID^.Object = valarg) or (ID^.Object = local) or
  665.        (ID^.Object = field) then
  666.         Write(' (', ID^.Offset, ') ');
  667.     Write(' : ');
  668.     WriteType(ID^.VType, Tabs, Primary)
  669.     end;
  670.     writeln(';');
  671. end;
  672.  
  673. Procedure Decompose;
  674. var
  675.     CB : BlockPtr;
  676.     ID : IDPtr;
  677.     TP : TypePtr;
  678.     i  : Integer;
  679. begin
  680.     Writeln("\nCurrent contents of the symbol table:");
  681.     CB := CurrentBlock;
  682.     while CB <> nil do begin
  683.     Writeln("\nLevel ", CB^.Level, "\n");
  684.     Writeln("Identifiers\n");
  685.     for i := 0 to Hash_Size do begin
  686.         ID := CB^.Table[i];
  687.         Writeln('Hash ', i);
  688.         while ID <> nil do begin
  689.         WriteID(ID, 0, True);
  690.         ID := ID^.Next;
  691.         end;
  692.     end;
  693.     Writeln("\nTypes\n");
  694.     TP := CB^.FirstType;
  695.     while TP <> nil do begin
  696.         WriteType(TP, 0, True);
  697.         Writeln;
  698.         TP := TP^.Next;
  699.     end;
  700.     CB := CB^.Previous;
  701.     end;
  702. end;
  703. }
  704.  
  705. Function CompareProcs(Proc1, Proc2 : IDPtr) : Boolean;
  706. var
  707.     ID1, ID2 : IDPtr;
  708. begin
  709.     if Proc1^.Object <> Proc2^.Object then
  710.     CompareProcs := False;
  711.     if Proc1^.Object = func then
  712.     if not TypeCmp(Proc1^.VType, Proc2^.VType) then
  713.         CompareProcs := False;
  714.     ID1 := Proc1^.Param;
  715.     ID2 := Proc2^.Param;
  716.     while (ID1 <> Nil) and (ID2 <> Nil) do begin
  717.     if not TypeCmp(ID1^.VType, ID2^.VType) then
  718.         CompareProcs := False;
  719.     ID1 := ID1^.Next;
  720.     ID2 := ID2^.Next;
  721.     end;
  722.     CompareProcs := ID1 = ID2;
  723. end;
  724.